package com.topisv.tms.service.ulorder;

import java.io.ByteArrayOutputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.xml.bind.JAXB;

import org.apache.commons.lang.StringUtils;
import org.apache.http.client.fluent.Request;
import org.apache.http.client.fluent.Response;
import org.apache.shiro.SecurityUtils;
//import org.fusesource.hawtbuf.ByteArrayOutputStream;
import org.hibernate.ejb.criteria.predicate.ComparisonPredicate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.topisv.tms.entity.AreaGroup;
import com.topisv.tms.entity.Customers;
import com.topisv.tms.entity.EdiGoodsSku;
import com.topisv.tms.entity.EdiOrder;
import com.topisv.tms.entity.EdiOrderItem;
import com.topisv.tms.entity.LogisticsCompany;
import com.topisv.tms.entity.QueryParamHolder;
import com.topisv.tms.entity.User;
import com.topisv.tms.entity.dto.CommonDto;
import com.topisv.tms.entity.log.OrderLog;
import com.topisv.tms.entity.stock.CusStock;
import com.topisv.tms.entity.ulorder.Ulorder;
import com.topisv.tms.entity.work.WorkOrder;
import com.topisv.tms.entity.work.WorkTaskItem;
import com.topisv.tms.exception.ErrorCode;
import com.topisv.tms.exception.PaiUException;
import com.topisv.tms.repository.AreaGroupDao;
import com.topisv.tms.repository.CustomersDao;
import com.topisv.tms.repository.EdiGoodsSkuDao;
import com.topisv.tms.repository.EdiOrderDao;
import com.topisv.tms.repository.EdiOrderItemDao;
import com.topisv.tms.repository.LogisticsCompanyDao;
import com.topisv.tms.repository.UserDao;
import com.topisv.tms.repository.log.OrderLogDao;
import com.topisv.tms.repository.stock.CusStockDao;
import com.topisv.tms.repository.ulorder.UlorderDao;
import com.topisv.tms.repository.work.WorkOrderDao;
import com.topisv.tms.repository.work.WorkTaskItemDao;
import com.topisv.tms.rest.entity.md.request.OrderConfirmDetail;
import com.topisv.tms.rest.entity.md.request.OrderConfirmRequestBody;
import com.topisv.tms.rest.entity.md.request.TransferBody;
import com.topisv.tms.rest.entity.md.request.TransferData;
import com.topisv.tms.rest.entity.md.request.TransferSubject;
import com.topisv.tms.rest.qimen.qmsend.QmRequestSender;
import com.topisv.tms.rest.qimen.qmservice.StockoutConfirmService;
import com.topisv.tms.service.account.ShiroDbRealm.ShiroUser;
import com.topisv.tms.service.base.BaseService;
import com.topisv.tms.service.vo.invoice.MDParam;
import com.topisv.tms.utils.SystemUtil;
import com.topisv.tms.utils.enums.MDDocumentType;
import com.topisv.tms.utils.enums.MDGoodsStatus;
import com.topisv.tms.utils.rule.TMSTransportRule;

/**
 * 线下定单_service
 * @author ch
 * @param <K>
 */
@Component
@Transactional(readOnly = true)
public class UlorderService<K> extends BaseService{
	protected Logger logger = LoggerFactory.getLogger(getClass());
	
	@Autowired
	private EdiOrderDao  ediOrderDao;
	@Autowired
	private UlorderDao ulorderDao;
	@Autowired
	private WorkOrderDao workOrderDao;
	@Autowired
	private CusStockDao cusStockDao;
	@Autowired
	private EdiOrderItemDao ediOrderItemDao;
	@Autowired
	private EdiGoodsSkuDao ediGoodsSkuDao;
	@Autowired
	private WorkTaskItemDao workTaskItemDao;
	@Autowired
	private CustomersDao customersDao;
	@Autowired
	private AreaGroupDao areaGroupDao;
	@Autowired
	private UserDao userDao;
	@Autowired
	private LogisticsCompanyDao logisticsCompanyDao;
	@Autowired
	private OrderLogDao orderLogDao;
	@Resource(type=StockoutConfirmService.class)
	private QmRequestSender<String> stockoutConfirmService;
	
	/**
	 * 创建线下订单
	 * @param customerCode 商家
	 * @param warehouseCode 仓库
	 * @param weight 重量
	 * @param companyCode 快递公司
	 * @param expressNo 运单号
	 * @param fromName 发件人姓名
	 * @param fromTel 发件人联系电话
	 * @param fromAddress 发件人地址
	 * @param toName 收件人姓名
	 * @param toTel 收件人电话
	 * @param toAddress 收件人地址
	 * @return
	 * @throws Exception 
	 */
	@Transactional(readOnly = false,rollbackFor=Exception.class)
	public Map<String, Object> createBill(Map<String, Integer> infoMap,String customerCode,
			String warehouseCode, String companyCode,
			String fromName, String fromTel,String fromAddress, 
			String toName, String toTel, String toAddress) throws Exception {
		try {
			Map<String, Object> result=new HashMap<String, Object>();
			Date now=new Date();
			ShiroUser user = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
			User curUser=this.userDao.findOne(user.id);
			
			/*//保存订单信息
			EdiOrder order=new EdiOrder();
			order.setCustomerCode(customerCode);
			order.setWarehouseCode(warehouseCode);
			order.setOrderStatus("ok");
			order.setStatus("finish");
			order.setRecena(toName);
			order.setTeleph(toTel);
			order.setCacode(companyCode);
			order.setOldCacode(companyCode);
			order.setOrdeno(TMSTransportRule.generateULBillCode());
			order.setAddres(toAddress);
			this.ediOrderDao.save(order);*/
			
			//保存商品信息
			List<CommonDto> pickInfoList=new ArrayList<CommonDto>();
			String errorList="";
			int goodsNum=0;
			StringBuilder goodsInfo=new StringBuilder();
			
			for(String sku:infoMap.keySet()){
				
				int sku_num = infoMap.get(sku); // 每个sku需求数量
				goodsNum+=sku_num; //商品数量合计
				goodsInfo.append(sku).append(":").append(sku_num).append(";");
				List<CusStock> stockList = this.cusStockDao.loadStock(warehouseCode, customerCode, sku);
				
				
				// 排序：库存数量升序排列，
				Collections.sort(stockList, new Comparator<CusStock>() {
					public int compare(CusStock o1, CusStock o2) {
						return o1.getSalesNum().compareTo(o2.getSalesNum());
					}
				});
				
				boolean flag = false;
				// 找到最接近满足的箱位
				for (CusStock cusStock : stockList) {
					if (cusStock.getSalesNum() >= sku_num) { 
						CommonDto dto=new CommonDto();
						dto.setField1(sku);
						dto.setField2(cusStock.getStockCode());
						dto.setField3(cusStock.getBoxCode());
						dto.setField4(sku_num);
						pickInfoList.add(dto);
						sku_num=0;
						flag = true;
						break;
					}
				}
				
				// 如果没有找到最接近的箱位，箱位组合分配。
				if (!flag) {
					Collections.reverse(stockList); // 排序，商品数量降序
					for (CusStock cusStock : stockList) {
						
						if (sku_num == 0){
							break;
						}
						
						int salesNum=cusStock.getSalesNum();
						if(salesNum<=sku_num){
							sku_num=sku_num-salesNum;
							CommonDto dto=new CommonDto();
							dto.setField1(sku);
							dto.setField2(cusStock.getStockCode());
							dto.setField3(cusStock.getBoxCode());
							dto.setField4(salesNum);
							pickInfoList.add(dto);
							
						}else if(salesNum>sku_num){
							CommonDto dto=new CommonDto();
							dto.setField1(sku);
							dto.setField2(cusStock.getStockCode());
							dto.setField3(cusStock.getBoxCode());
							dto.setField4(sku_num);
							pickInfoList.add(dto);
							sku_num=0;
						}
					}
				}
				if(sku_num>0){
					if(errorList.length()>0){
						errorList+=",";
					}
					errorList+=sku;
				}
			}
			
			//保存订单信息
			EdiOrder order=new EdiOrder();
			order.setCustomerCode(customerCode);
			order.setWarehouseCode(warehouseCode);
			order.setOrderStatus("ok");
			order.setStatus("finish");
			order.setRecena(toName);
			order.setTeleph(toTel);
			order.setCacode(companyCode);
			order.setOldCacode(companyCode);
			order.setOrdeno(TMSTransportRule.generateULBillCode());
			order.setAddres(toAddress);
			order.setSkuQty(goodsNum);
			this.ediOrderDao.save(order);
			
			if(errorList.length()>0){  //如果有商品不能满足库存，返回
				result.put("msg","error_goods");
				result.put("content",errorList);
				return result;
			}
			
			//修改库存信息
			for (CommonDto dto : pickInfoList) {
				String sku=(String) dto.getField1();
				String stockCode=(String) dto.getField2();
				String boxCode=(String) dto.getField3();
				Integer num=(Integer) dto.getField4();
				
				CusStock stock=this.cusStockDao.loadStock(customerCode, warehouseCode, stockCode, boxCode, sku);
				stock.setSalesNum(stock.getSalesNum()-num); //减少可销售库存
				stock.setOrderNum(stock.getOrderNum()+num); //添加订单占用库存
				this.cusStockDao.save(stock);
				
				//创建拣货明细
				WorkTaskItem taskItem=new WorkTaskItem();
				taskItem.setBoxCode(boxCode);
				taskItem.setWarehouseCode(warehouseCode);
				taskItem.setCustomerCode(customerCode);
				taskItem.setStockCode(stockCode);
				taskItem.setSku(sku);
				taskItem.setNum(num);
				taskItem.setOrderno(order.getOrdeno());
				taskItem.setPickedNum(0);
				taskItem.setPickStatus("unpicked");
				this.workTaskItemDao.save(taskItem);
				
			}
			
			//保存订单明细
            for(String sku:infoMap.keySet()){
				int num = infoMap.get(sku); // 每个sku需求数量
				
				EdiOrderItem item=new EdiOrderItem();
				item.setOrdeno(order.getOrdeno());
				item.setSku(sku);
				item.setQty(num);
				this.ediOrderItemDao.save(item);
            }
			
			//保存线下订单信息
			Ulorder uo=new Ulorder();
			uo.setOrderno(order.getOrdeno());
			uo.setCustomerCode(customerCode);
			uo.setWarehouseCode(warehouseCode);
			uo.setExpCompany(companyCode);
			uo.setFromAddress(fromAddress);
			uo.setFromName(fromName);
			uo.setFromTel(fromTel);
			uo.setToAddress(toAddress);
			uo.setToName(toName);
			uo.setToTel(toTel);
			uo.setCreateTime(now);
			uo.setCreaterUuid(user.jobuuid);
			uo.setStatus("login"); //状态 (login:已登记     send:已发货 )
			uo.setGoodsStatus("normal");
			this.ulorderDao.save(uo);
			
			//保存作业单信息
			WorkOrder wo=new WorkOrder();
			wo.setCancelStatus("ok");
			wo.setStatus("2"); //订单状态 (1.创建批次 2.创建任务 3.已拣货 4.已灯光拣选 9.待包装 5.已包装 6.已发货 7.已签收 8.异常 )
			wo.setCustomerCode(customerCode);
			wo.setWarehouseCode(warehouseCode);
			wo.setCreateTime(now);
			wo.setOrder(order);
			wo.setExpressCompany(companyCode);
			wo.setGoodsInfo(goodsInfo.toString());
			wo.setGoodsNum(goodsNum);
			this.workOrderDao.save(wo);
			
			//写日志
			OrderLog log=new OrderLog(
					uo.getOrderno(),
					uo.getCustomerCode(),
					"2", //操作类型 （1.创建批次 2.创建任务  3.拣货完成 4.包装完成 5.发货完成 6.签收完成 7.异常登记 8.完成灯光拣选任务 9.打印单据 ）
					curUser,
					now,
					null,
					user.getRealname()+"登记线下订单");
			this.orderLogDao.save(log);
			
			
			result.put("msg","success");
			return result;
			
		} catch (Exception e) {
			throw e;
		}
	}
	
	/**
	 * 创建线下订单
	 * @param EdiOrder 订单
	 * @return
	 * @throws Exception 
	 */
	@Transactional(readOnly = false,rollbackFor=Exception.class)
	public void createBill_2(EdiOrder ediOrder) throws Exception {
			Date now=new Date();
			ediOrder.setOrderStatus("ok");
			ediOrder.setStatus("finish");
			if(null == ediOrder.getCacode() ||"".equals(ediOrder.getCacode()))
			{
				ediOrder.setCacode("TTKDEX");
			}
			
			//ediOrder.setOrdeno(TMSTransportRule.generateULBillCode());
			this.ediOrderDao.save(ediOrder);
			
			
			int goodsNum=0;
			StringBuilder goodsInfo=new StringBuilder();
			
            List<EdiOrderItem> orderItems = ediOrder.getSkulst();
			Date nowDate = new Date();
			String goodsStatus="";
			for (EdiOrderItem ei : orderItems) {
				ei.setCrtime(nowDate);
				ei.setWaybillNo(ediOrder.getWaybillNo());
				ei.setCustomerCode(ediOrder.getCustomerCode());
				ei.setOrdeno(ediOrder.getOrdeno());
				goodsInfo.append(ei.getSku()).append(":").append(ei.getQty()).append(";");
				ediOrderItemDao.save(ei);
				goodsNum += ei.getQty();
				goodsStatus = ei.getOidStatus();
			}
			ediOrder.setSkuQty(goodsNum);
			
			
			//保存商品信息
			List<CommonDto> pickInfoList=new ArrayList<CommonDto>();
			String errorList="";
			for(EdiOrderItem ei : orderItems){
				
				int sku_num = ei.getQty(); // 每个sku需求数量
				List<CusStock> stockList = this.cusStockDao.loadStock(ediOrder.getWarehouseCode(), ediOrder.getCustomerCode(), ei.getSku());
				logger.info("WarehouseCode== " +ediOrder.getWarehouseCode() + ",CustomerCode==" + ediOrder.getCustomerCode() + ",sku=="  +ei.getSku());
				
				// 排序：库存数量升序排列，
				if("normal".equals(goodsStatus))
				{
					Collections.sort(stockList, new Comparator<CusStock>() {
						public int compare(CusStock o1, CusStock o2) {
							return o1.getSalesNum().compareTo(o2.getSalesNum());
						}
					});
				}
				else
				{
					Collections.sort(stockList, new Comparator<CusStock>() {
						public int compare(CusStock o1, CusStock o2) {
							return o1.getUnusedNum().compareTo(o2.getUnusedNum());
						}
					});
				}
				
				
				boolean flag = false;
				// 找到最接近满足的箱位
				for (CusStock cusStock : stockList) {
					int _sku_num =0;
					if("normal".equals(goodsStatus))
					{
						_sku_num=cusStock.getSalesNum();
					}
					else
					{
						_sku_num=cusStock.getUnusedNum();
					}
					if (_sku_num >= sku_num) { 
						CommonDto dto=new CommonDto();
						dto.setField1(ei.getSku());
						dto.setField2(cusStock.getStockCode());
						dto.setField3(cusStock.getBoxCode());
						dto.setField4(sku_num);
						pickInfoList.add(dto);
						sku_num=0;
						flag = true;
						break;
					}
				}
				
				// 如果没有找到最接近的箱位，箱位组合分配。
				if (!flag) {
					Collections.reverse(stockList); // 排序，商品数量降序
					for (CusStock cusStock : stockList) {
						
						if (sku_num == 0){
							break;
						}
						
						int salesNum=0;
						if("normal".equals(goodsStatus))
						{
							salesNum=cusStock.getSalesNum();
						}
						else
						{
							salesNum=cusStock.getUnusedNum();
						}
						if(salesNum<=sku_num){
							sku_num=sku_num-salesNum;
							CommonDto dto=new CommonDto();
							dto.setField1(ei.getSku());
							dto.setField2(cusStock.getStockCode());
							dto.setField3(cusStock.getBoxCode());
							dto.setField4(salesNum);
							pickInfoList.add(dto);
							
						}else if(salesNum>sku_num){
							CommonDto dto=new CommonDto();
							dto.setField1(ei.getSku());
							dto.setField2(cusStock.getStockCode());
							dto.setField3(cusStock.getBoxCode());
							dto.setField4(sku_num);
							pickInfoList.add(dto);
							sku_num=0;
						}
					}
				}
				
				if(sku_num>0){
					if(errorList.length()>0){
						errorList+=",";
					}
					errorList+=ei.getSku();
				}
			}
			
			if(errorList.length()>0){  //如果有商品不能满足库存，返回
				logger.info("出库库存不足== " + errorList);
				throw new PaiUException(ErrorCode.STOCK_NOT_ENOUGH);
			}
			
			//修改库存信息
			for (CommonDto dto : pickInfoList) {
				String sku=(String) dto.getField1();
				String stockCode=(String) dto.getField2();
				String boxCode=(String) dto.getField3();
				Integer num=(Integer) dto.getField4();
				logger.info("WarehouseCode== " +ediOrder.getWarehouseCode() + ",CustomerCode==" + ediOrder.getCustomerCode() +",stockCode== " +stockCode + ",boxCode==" + boxCode + ",sku=="  +sku);
				CusStock stock=this.cusStockDao.loadStock( ediOrder.getCustomerCode(),ediOrder.getWarehouseCode(), stockCode, boxCode, sku);
				if("normal".equals(goodsStatus))
				{
					stock.setSalesNum(stock.getSalesNum()-num); //减少可销售库存
					stock.setOrderNum(stock.getOrderNum()+num); //添加订单占用库存
				}
				else
				{
					stock.setUnusedNum(stock.getUnusedNum()-num); //减少可销售库存
				}
				this.cusStockDao.save(stock);
				
				//创建拣货明细
				WorkTaskItem taskItem=new WorkTaskItem();
				taskItem.setBoxCode(boxCode);
				taskItem.setWarehouseCode(ediOrder.getWarehouseCode());
				taskItem.setCustomerCode(ediOrder.getCustomerCode());
				taskItem.setStockCode(stockCode);
				taskItem.setSku(sku);
				taskItem.setNum(num);
				taskItem.setOrderno(ediOrder.getOrdeno());
				taskItem.setPickedNum(num);
				taskItem.setPickStatus("picked");
				this.workTaskItemDao.save(taskItem);
				
			}
			
			//保存线下订单信息
			Ulorder uo=new Ulorder();
			uo.setOrderno(ediOrder.getOrdeno());
			uo.setCustomerCode(ediOrder.getCustomerCode());
			uo.setWarehouseCode(ediOrder.getWarehouseCode());
			uo.setCustomerOrdeno(ediOrder.getCustomerOrdeno());
			uo.setExpCompany(ediOrder.getCacode());
			uo.setFromAddress("1");
			uo.setFromName("1");
			uo.setFromTel("1");
			uo.setToAddress(ediOrder.getAddres());
			uo.setToName(ediOrder.getRecena());
			uo.setToTel(ediOrder.getMobile());
			uo.setCreateTime(now);
			uo.setGoodsStatus(goodsStatus);
			uo.setCreaterUuid("ADMIN");
			uo.setStatus("login"); //状态 (login:已登记     send:已发货 )
			this.ulorderDao.save(uo);
			
			//保存作业单信息
			WorkOrder wo=new WorkOrder();
			wo.setCancelStatus("ok");
			wo.setStatus("3"); //订单状态 (1.创建批次 2.创建任务 3.已拣货 4.已灯光拣选 9.待包装 5.已包装 6.已发货 7.已签收 8.异常 )
			wo.setCustomerCode(ediOrder.getCustomerCode());
			wo.setWarehouseCode(ediOrder.getWarehouseCode());
			wo.setCreateTime(now);
			wo.setOrder(ediOrder);
			wo.setExpressCompany(ediOrder.getCacode());
			wo.setGoodsInfo(goodsInfo.toString());
			wo.setGoodsNum(goodsNum);
			this.workOrderDao.save(wo);
			
			//写日志
			OrderLog log=new OrderLog(
					uo.getOrderno(),
					uo.getCustomerCode(),
					"2", //操作类型 （1.创建批次 2.创建任务  3.拣货完成 4.包装完成 5.发货完成 6.签收完成 7.异常登记 8.完成灯光拣选任务 9.打印单据 ）
					null,
					now,
					null,
					"系统"+"登记线下订单");
			this.orderLogDao.save(log);

	}
	
	/**
	 * 创建线下订单
	 * @param EdiOrder 订单
	 * @return
	 * @throws Exception 
	 */
	@Transactional(readOnly = false,rollbackFor=Exception.class)
	public void cancelBill(String customerOrdeno) throws Exception {
		try {
			Date now=new Date();
			
			Ulorder ulorder=this.ulorderDao.loadByCustomerOrdeno(customerOrdeno);
			if(null == ulorder)
			{
				logger.info("出库取消：order:"+customerOrdeno+" 订单不存在");
				throw new PaiUException(ErrorCode.CANCEL_NO_EXIST);
			}
			if("send".equals(ulorder.getStatus()))
			{
				logger.info("出库取消：order:"+customerOrdeno+" 订单已经发货 取消失败");
				throw new PaiUException(ErrorCode.CANCEL_NO_EXIST);
			}
			if("cancel".equals(ulorder.getStatus()))
			{
				logger.info("出库取消：order:"+customerOrdeno+" 已经取消");
				return;
			}
			ulorder.setStatus("cancel");
			this.ulorderDao.save(ulorder);
			
			
			List<EdiOrder> ediOrders = this.ediOrderDao.findByCustomerCodeAndCustomerOrdeno(ulorder.getCustomerCode(), customerOrdeno);
			EdiOrder ediOrder = ediOrders.get(0);
			ediOrder.setOrderStatus("cancel");
			this.ediOrderDao.save(ediOrder);
			List<WorkTaskItem> itemList=this.workTaskItemDao.loadByOrderno(ediOrder.getOrdeno());
			for (WorkTaskItem workTaskItem : itemList) {
				Integer num=workTaskItem.getNum();
				String sku=workTaskItem.getSku();
				String boxCode=workTaskItem.getBoxCode();
				String stockCode=workTaskItem.getStockCode();
				String warehouseCode=workTaskItem.getWarehouseCode();
				String customerCode=workTaskItem.getCustomerCode();
				
				//修改库存信息
				CusStock stock=this.cusStockDao.loadStock(customerCode,warehouseCode,stockCode,boxCode,sku);
				if(null == stock)
				{
					Customers customer=this.customersDao.findByCustomerCode(customerCode);
					stock = new CusStock();
					stock.setCustomerCode(customerCode);
					stock.setWarehouseCode(warehouseCode);
					stock.setStockCode(stockCode);
					stock.setBoxCode(boxCode);
					stock.setSku(sku);
					stock.setCustomer(customer);
					stock.setStockType("1");
					stock.setUnusedNum(0);
					stock.setSalesNum(0);
					stock.setOrderNum(0);
					stock.setAirNum(0);
					stock.setLockedNum(0);
					stock.setTransportNum(0);
				}
				if("normal".equals(ulorder.getGoodsStatus()))
				{
					stock.setSalesNum(stock.getSalesNum()+num); //减少可销售库存
					stock.setOrderNum(stock.getOrderNum()-num); //添加订单占用库存
				}
				else
				{
					stock.setUnusedNum(stock.getUnusedNum()+num);
				}
				
				
				this.cusStockDao.save(stock);
				
			}
			
			
			WorkOrder wo = this.workOrderDao.findByOrder(ediOrder.getOrdeno());
			wo.setCancelStatus("cancel");
			this.workOrderDao.save(wo);
			
			//写日志
			OrderLog log=new OrderLog(
					wo.getOrder().getOrdeno(),
					wo.getCustomerCode(),
					"7", //操作类型 （1.创建批次 2.创建任务  3.拣货完成 4.包装完成 5.发货完成 6.签收完成 7.异常登记 8.完成灯光拣选任务 9.打印单据 ）
					null,
					now,
					null,
					"取消订单");
			this.orderLogDao.save(log);
			
		} catch (Exception e) {
			logger.error("取消失败",e);
			throw e;
		}
	}

	public Page<Ulorder> loadPageByParam(QueryParamHolder paramHolder) {
	    Specification<Ulorder> spec =this.getWhereClause(paramHolder.getSearchParams());
	    Page<Ulorder> page = findByJson(paramHolder, ulorderDao, spec, Ulorder.class);
	  
	    for (Ulorder o : page.getContent()) {
			this.setDetail(o);
		}
	    return page;
	}

	/**
	 * 设置明细
	 * @param o
	 */
	private void setDetail(Ulorder o) {
		
		//customer
		String customerCode=o.getCustomerCode();
		Customers customer=this.customersDao.findByCustomerCode(customerCode);
		o.setCustomer(customer);
		
		//warehouse
		String warehouseCode=o.getWarehouseCode();
		AreaGroup warehouse=this.areaGroupDao.findByGroupCode(warehouseCode);
		o.setWarehouse(warehouse);
		
		//creater
		User user=this.userDao.findByJobuuid(o.getCreaterUuid());
		o.setCreater(user);
		
		//sender
		User sender=this.userDao.findByJobuuid(o.getSenderUuid());
		o.setSender(sender);
		
		//company
		LogisticsCompany company=this.logisticsCompanyDao.findCompanyByCode(o.getExpCompany());
		o.setCompany(company);
		
	}

	/**
	 * 查询条件封装
	 * @param searchParams
	 * @return
	 */
	private Specification<Ulorder> getWhereClause(final Map<String, Object> searchParams) {
		return new Specification<Ulorder>(){
		    @Override
		    public Predicate toPredicate(Root<Ulorder> r, CriteriaQuery<?> q, CriteriaBuilder cb) {
		      Predicate pre = cb.conjunction();
		      
		      //customerCodes
		      String customerCodes=(String) searchParams.get("customerCodes");
		      if(StringUtils.isNotBlank(customerCodes)) {
		    	  String[] customerCodeSplit = customerCodes.split(":");
				  ComparisonPredicate[] tempCustomerCode = new ComparisonPredicate[customerCodeSplit.length];
				  int i = 0;
				  for (String _customerCode : customerCodeSplit) {
					 tempCustomerCode[i] = (ComparisonPredicate) cb.equal(r.get("customerCode"), _customerCode);
					 i++;
				  }
				  pre.getExpressions().add(cb.or(tempCustomerCode));
		      }
			  
		      //areagroups
		      String areagroups=(String) searchParams.get("areagroups");
		      if(StringUtils.isNotBlank(areagroups)) {
		    	  String[] areagroupSplit = areagroups.split(":");
				  ComparisonPredicate[] areagroupArray = new ComparisonPredicate[areagroupSplit.length];
				  int j = 0;
				  for (String _areagroup : areagroupSplit) {
						areagroupArray[j] = (ComparisonPredicate) cb.equal(r.get("warehouseCode"), _areagroup);
						j++;
				  }
				  pre.getExpressions().add(cb.or(areagroupArray));
			  }
		      
		      //能容订单号或快递单号或客户订单号
		      String allOrderno=(String) searchParams.get("allOrderno");
		      if(StringUtils.isNotEmpty(allOrderno)){
				pre.getExpressions().add(
					cb.or(
							cb.like(r.<String>get("orderno"),"%"+allOrderno.trim()+"%"),
							cb.like(r.<String>get("customerOrdeno"),"%"+allOrderno.trim()+"%"),
							cb.like(r.<String>get("expNo"),"%"+allOrderno.trim()+"%")
					));
		      }
		      
		      //开始时间
		      Object fromDate=  searchParams.get("fromDate1");
		      if (fromDate != null) {
		        pre.getExpressions().add(cb.greaterThanOrEqualTo(r.<Date>get("createTime"), (Date)fromDate));
		      }
		      
		      //结束时间
		      Object toDate=searchParams.get("toDate1");
		      if (toDate != null) {
		        pre.getExpressions().add(cb.lessThanOrEqualTo(r.<Date>get("createTime"), (Date)toDate));
		      }
		      
		      //状态
		      String status=(String) searchParams.get("status");
		      if (StringUtils.isNotBlank(status)) {
		        pre.getExpressions().add(cb.equal(r.get("status"), status));
		      }
		      
		      return pre;
		    }
		  };
       }

	/**
	 * 查询
	 * @param orderno
	 * @return
	 */
	public Ulorder loadByOrderno(String orderno) {
		Ulorder ulorder= this.ulorderDao.loadByOrderno(orderno);
		this.setDetail(ulorder);
		return ulorder;
	}
	
	/**
	 * 发货单确认（重发接口）
	 *
	 * @param 
	 * @return 
	 * @throws 
	 * @author yuansheng
	 * @version 1.0.0
	 * @throws Exception 
	 */
	public String ajaxResend(String orderNo) throws Exception{
	    EdiOrder order = ediOrderDao.findByOrdeno(orderNo);
	    if(order == null){
	        return "订单不存在";
	    }
	    String result= stockoutConfirmService.send(orderNo, order.getCustomerCode());
        return result;
	}

	/**
	 * 发货
	 * @param orderno
	 * @param weight
	 * @param expressNo
	 * @throws Exception 
	 */
	@Transactional(readOnly = false,rollbackFor=Exception.class)
	public void send(String orderno, String weight, String expressNo) throws Exception {
		try {
			ShiroUser user = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
			User curUser=this.userDao.findOne(user.id);
			Date now=new Date();
			
			//保存重量、快递单号信息
			Ulorder ulorder=this.ulorderDao.loadByOrderno(orderno);
			ulorder.setWeight(Integer.valueOf(weight));
			ulorder.setExpNo(expressNo);
			ulorder.setStatus("send");  //状态( login: 已登记 send: 已发货 )
			this.ulorderDao.save(ulorder);
			
			//修改WorkOrder状态
			WorkOrder workOrder=this.workOrderDao.loadByOrderno(orderno);
			workOrder.setExpressNo(expressNo);
			workOrder.setWeight(Integer.valueOf(weight));
			workOrder.setStatus("6"); //订单状态 (1.创建批次 2.创建任务 3.已拣货 4.已灯光拣选 9.待包装 5.已包装 6.已发货 7.已签收 8.异常 )
			workOrder.setFinishTime(now);
			this.workOrderDao.save(workOrder);
			if("MID".equals(workOrder.getCustomerCode()) && workOrder.getOrder().getCustomerOrdeno() != null)
			{
				send_2(workOrder);
			}
			// 商家出库是否开通奇门接口
			String customerCodeQm =  workOrder.getCustomerCode();
			if (StringUtils.isNotBlank(customerCodeQm) ) {
				Customers customers = customersDao.findByCustomerCode(customerCodeQm);
				if (StringUtils.equals("1", customers.getOpenQm())) {
					String result= stockoutConfirmService.send(orderno, customerCodeQm);
					if (StringUtils.equals("failure", result)) {
						throw new Exception("exception message : qmsend error。 orderno["+orderno+"]");
					}
				}
			}
			if("normal".equals(ulorder.getGoodsStatus()))
			{
				//修改workTaskItem、库存信息
				List<WorkTaskItem> itemList=this.workTaskItemDao.loadByOrderno(orderno);
				for (WorkTaskItem workTaskItem : itemList) {
					workTaskItem.setPickedNum(workTaskItem.getNum());
					workTaskItem.setPickStatus("picked");
					Integer num=workTaskItem.getNum();
					String sku=workTaskItem.getSku();
					String boxCode=workTaskItem.getBoxCode();
					String stockCode=workTaskItem.getStockCode();
					String warehouseCode=workTaskItem.getWarehouseCode();
					String customerCode=workTaskItem.getCustomerCode();
					
					//修改库存信息
					CusStock stock=this.cusStockDao.loadStock(customerCode,warehouseCode,stockCode,boxCode,sku);
					if(stock.getOrderNum()-num<0){
						throw new Exception("exception message : ordernum is error。 orderno["+orderno+"] sku["+sku+"]");
					}
					stock.setOrderNum(stock.getOrderNum()-num);
					this.cusStockDao.save(stock);
					this.workTaskItemDao.save(itemList);
				}
			}
			//写日志
			OrderLog log=new OrderLog(
					ulorder.getOrderno(),
					ulorder.getCustomerCode(),
					"5", //操作类型 （1.创建批次 2.创建任务  3.拣货完成 4.包装完成 5.发货完成 6.签收完成 7.异常登记 8.完成灯光拣选任务 9.打印单据）
					curUser,
					now,
					null,
					user.getRealname()+"完成线下单发货操作");
			this.orderLogDao.save(log);
			
		} catch (Exception e) {
			throw e;
		}
		
	}
	
	public void send_2(WorkOrder workOrder) throws Exception {
		logger.info("美的返厂出库反馈：start，");
		TransferData transferData = new TransferData(); 
		TransferSubject transferSubject = new TransferSubject();
		transferSubject.setSender("PaiUEB");
		transferSubject.setReceiver("AnntoOMS");
		transferSubject.setDataGenerationTime(new Date());
		transferSubject.setTransferFileID(TMSTransportRule.generateByPreFix("CIO"));
		transferSubject.setDocumentType(MDDocumentType.ORDERCONFIM.getSubjectType());
		transferSubject.setSign("");
		transferSubject.setVersion("1.0");
		
		OrderConfirmRequestBody orderConfirmRequestBody = new OrderConfirmRequestBody();
		
		orderConfirmRequestBody.setCustOrdNo(workOrder.getOrder().getCustomerOrdeno());
		orderConfirmRequestBody.setWhCode(workOrder.getOrder().getCusWarehouseCode());
		orderConfirmRequestBody.setWhName("");
		orderConfirmRequestBody.setCustCustomerCode(workOrder.getOrder().getSubCustomerCode());
		orderConfirmRequestBody.setOrderType("07");
		orderConfirmRequestBody.setWeight(Double.valueOf(workOrder.getWeight()));
		orderConfirmRequestBody.setCarrierCode(workOrder.getExpressCompany());
		orderConfirmRequestBody.setExpressNo(workOrder.getExpressNo());
		orderConfirmRequestBody.setProcessTime(new Date());
		orderConfirmRequestBody.setInvoiceFlag("N");
		
		logger.info("美的返厂出库反馈：查询盘点出入库明细表，");
		List<EdiOrderItem> items = ediOrderItemDao.findByOrdeno(workOrder.getOrder().getOrdeno());
		
		List<OrderConfirmDetail> ocdList = new ArrayList<OrderConfirmDetail>();
			for(EdiOrderItem item:items){
				OrderConfirmDetail detail = new OrderConfirmDetail();
				EdiGoodsSku ediGoodsSku = ediGoodsSkuDao.findByCustomerCodeAndSku(workOrder.getCustomerCode(), item.getSku());
				
				detail.setLineNo(item.getLineNo());
				detail.setCustGoodsCode(ediGoodsSku.getBar());
				detail.setPlanQty(item.getQty());
				detail.setQty(item.getQty());
				detail.setGoodsStatus(MDGoodsStatus.OTHERS.getType());
				detail.setCarrierCode(workOrder.getExpressCompany());//
				detail.setExpressNo(workOrder.getExpressNo());
				detail.setVolume(StringUtils.isBlank(item.getVol()) ? null : Double.valueOf(item.getVol()));
				detail.setPackageWeight(workOrder.getWeight());
				detail.setInvoiceNo(workOrder.getInvoiceNo());
				detail.setInvoiceBy(workOrder.getInvoiceOperate());
				detail.setInvoiceTime(new Date());
				ocdList.add(detail);
			}
		orderConfirmRequestBody.setConfigDetails(ocdList);
		
		logger.info("美的返厂出库反馈：设置xml映射类值，");
		
		transferData.setTransferSubject(transferSubject);
		TransferBody transferBody = new TransferBody();
		transferBody.setContent(orderConfirmRequestBody);
		transferData.setTransferBody(transferBody);
		
		logger.info("美的返厂出库反馈：xml映射类转换xml，");
		ByteArrayOutputStream bais = new ByteArrayOutputStream(1024);
		JAXB.marshal(transferData, bais);
		
		StringWriter writer = new StringWriter();
		JAXB.marshal(transferData,writer);
		logger.info("美的返厂出库反馈：发送报文:"+writer.toString());
		
		
		logger.info("美的返厂出库反馈：开始发送反馈消息，");
		Response response = sendOutMessage(bais);
		com.topisv.tms.rest.entity.md.response.Response mdResponse = JAXB.unmarshal(response.returnContent().asStream(), com.topisv.tms.rest.entity.md.response.Response.class);
		if (mdResponse.isFlag()) {
			logger.info("美的返厂出库反馈消息发送完成 结果成功"+mdResponse);
		}else {
			logger.info("美的返厂出库反馈消息发送完成 结果异常"+mdResponse);
			throw new PaiUException(ErrorCode.CHECK_BACK_INFO_ERROR);
		}
		StringWriter writerResop = new StringWriter();
		JAXB.marshal(mdResponse,writerResop);
		logger.info("美的返厂出库反馈：响应报文:"+writerResop.toString());
		
		logger.info("美的返厂出库反馈：end，");
	}
	
	private Response sendOutMessage(ByteArrayOutputStream bais) throws Exception{
		String token = new StringBuilder().append(MDParam.USERNAME).append(":").append(MDParam.PASSWORD).toString();
		return Request.Post(MDParam.URL).connectTimeout(10000)
				.addHeader("Authorization", new StringBuilder().append("Basic ").append(SystemUtil.getBASE64(token)).toString())
				.addHeader("Content-Type", "text/xml; charset=utf-8").bodyByteArray(bais.toByteArray()).execute();
	}
	
	/**
	 * 根据客户编码和客户订单号判断客户订单是否存在
	 * 
	 * @param customerCode 客户编码
	 * @param customerOrdeno 客户订单号
	 * @return
	 */
	public HashMap<String, Ulorder> isOwnerOrdeno (String customerCode, String customerOrdeno ) {
		
		HashMap<String, Ulorder> ulorderMap = new HashMap<String, Ulorder>();
		Ulorder ulorder = ulorderDao.getOwnerOrdeno(customerCode, customerOrdeno);
		
		// 判断线下订单是否是取消状态
		if (null != ulorder && StringUtils.isNotBlank(ulorder.getOrderno()) && 
				StringUtils.equals(ulorder.getStatus(), "cancel")) {
			EdiOrder ediOrder = ediOrderDao.getCustomerOrdeno(customerCode,customerOrdeno);
			// 判断线上订单是否是取消状态
			if (null != ediOrder && StringUtils.equals(ediOrder.getOrderStatus(), "cancel")) {
				WorkOrder workOrder = workOrderDao.findByOrder(ediOrder.getOrdeno());
				// 作业订单是否是取消状态
				if (null != ediOrder && StringUtils.equals(workOrder.getCancelStatus(), "cancel")) {
					ulorderMap.put("1", ulorder);
				}
			}
		} else {
			ulorderMap.put("0", ulorder);
		}
		return ulorderMap;
	}
	
	/**
	 * 根据客户编码和客户订单好查询查询客户订单是否存在
	 * 
	 * @param customerCode
	 * @param customerOrdeno
	 * @return
	 */
	public Ulorder getCustomerOrder(String customerCode, String customerOrdeno ) {
		Ulorder ulorder = null;
		try {
			
			ulorder = ulorderDao.getOwnerOrdeno(customerCode, customerOrdeno);
			
		}catch (Exception e){
			logger.error("system query error",e);
		}
		 return ulorder;
	}
}